package com.xx.bysj.service.imp;

import cn.hutool.crypto.digest.BCrypt;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xx.bysj.BysjApplication;
import com.xx.bysj.dto.HnInformation;
import com.xx.bysj.dto.HnOrder;
import com.xx.bysj.dto.HnUser;
import com.xx.bysj.dto.UploadFileDto;
import com.xx.bysj.mapper.HnInformationMapper;
import com.xx.bysj.mapper.HnOrderMapper;
import com.xx.bysj.mapper.HnUserMapper;
import com.xx.bysj.service.UserService;
import com.xx.bysj.utils.Base64Utils;
import com.xx.bysj.utils.NumberUtils;
import com.xx.bysj.utils.Result;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.Binary;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;

import static com.xx.bysj.utils.RedisConstants.REGISTER_CODE_KEY;

@Service
//开启事务回滚
@Transactional(rollbackFor = Exception.class)
public class UserServiceImp implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(BysjApplication.class);

    @Autowired
    private HnUserMapper userMapper;

    @Autowired
    private HnInformationMapper informationMapper;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private HnOrderMapper orderMapper;

    @Override
    public Result register(HnUser user, String type) {
        if (StringUtils.isBlank(user.getEmailCode())
                || StringUtils.isBlank(user.getUserEmail()) ){
            return Result.fail("邮箱或验证码错误，请重试");
        }
        // 判断验证码是否过期
        String redisCode = stringRedisTemplate.opsForValue().get(REGISTER_CODE_KEY + user.getUserEmail());
        if (StringUtils.isBlank(redisCode)){
            return Result.fail("验证码已过期");
        }
        if (!redisCode.equals(user.getEmailCode())){
            return Result.fail("验证码错误");
        }
        if("common".equals(type)){
            user.setUserRoleId(1);
        }else{
            user.setUserRoleId(0);
        }
        // 密码加密
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        user.setUserPassword(passwordEncoder.encode(user.getUserPassword()));
        user.setVersionNumber(0);
        List<HnUser> hnUserList = userMapper.selectByUserNameList(user);
        if(hnUserList.size() != NumberUtils.ZERO){
            return Result.fail("当前用户已存在");
        }else{
            try {
                userMapper.insertSelective(user);
                return Result.success("注册成功");
            }catch (Exception e){
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public Result updateUserInformation(HnInformation hnInformation) {
        HnUser user = new HnUser();
        user.setUserName(hnInformation.getUserName());
        HnUser thisUser = userMapper.selectByUserName(user);
        List<HnInformation> informations = informationMapper.selectByUserId(thisUser.getUserId());
        hnInformation.setUserId(thisUser.getUserId());
        try {
            if (CollectionUtils.isNotEmpty(informations)) {
                // 修改
                informationMapper.updateByUserId(hnInformation);
            } else {
                informationMapper.insertSelective(hnInformation);
            }
        }catch (Exception e){
            throw new RuntimeException("系统错误");
        }
        return Result.success("修改成功");
    }

    @Override
    public Result query(HnInformation information,int page, int pageSize) {
        PageHelper.startPage(page,pageSize);
        List<HnInformation> informations = informationMapper.query(information);
        PageInfo<HnInformation> pageInfo = new PageInfo<>(informations);
        return Result.querySuccess(informations,(int)pageInfo.getTotal());
    }

    @Override
    public void mongoDbShow(String id, HttpServletResponse response) {
        byte[] data = null;
        UploadFileDto file = mongoTemplate.findById(id, UploadFileDto.class);
        if (file != null) {
            data = file.getContent().getData();
        }
        if (null != data) {
            try (ServletOutputStream ot = response.getOutputStream()) {
                ot.write(data, 0, data.length);
                ot.flush();
            } catch (Exception e) {
                throw new NullPointerException("无法获取图片信息!");
            }
        }
        response.setContentType("image/jpeg, image/jpg, image/png, image/gif");
    }

    @Override
    public Result uploadMongoDb(MultipartFile file, HttpServletRequest request, Authentication authentication) {
        if (file.isEmpty()){
            return Result.fail("文件为空，请选择文件");
        }
        try {
            // 赋值上传图片的属性
            String fileName = file.getOriginalFilename();
            UploadFileDto uploadFile = new UploadFileDto()
                    .setName(fileName)
                    .setCreatedTime(LocalDateTime.now())
                    .setContent(new Binary(file.getBytes()))
                    .setContentType(file.getContentType())
                    .setSize(file.getSize());

            // 通过 mongoTemplate 保存后，会把数据库自动生成的主键赋值到这个对象上
            UploadFileDto savedFile = mongoTemplate.save(uploadFile);
            // 构造好这个图片的请求地址返回给前端，我们后面实现这个请求
            String url = "/user/mongoDbShow/" + savedFile.getId();
            return Result.success("上传成功",url);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result distributeRole(HnUser user) {
        try {
            userMapper.updateByPrimaryKeySelective(user);
        } catch (Exception e) {
            logger.info(e.toString());
            throw new RuntimeException("分配角色失败");
        }
        return Result.success("分配角色成功");
    }

    @Override
    public Result updateUserPassword(HnUser user, Authentication authentication) {
        if (StringUtils.isEmpty(user.getUserPassword()) || StringUtils.isEmpty(user.getUserNewPassword())
                || StringUtils.isEmpty(user.getUserCheckPassword())) {
            return Result.fail("请输入原密码/新密码/确认密码");
        }
        if (null == user.getUserId()) {
            return Result.fail("未知错误请联系管理员");
        }
        HnUser hnUser = userMapper.selectByPrimaryKey(user.getUserId());
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        if (!passwordEncoder.matches(user.getUserPassword(),hnUser.getUserPassword())) {
            return Result.fail("原密码错误");
        }
        if (!user.getUserNewPassword().equals(user.getUserCheckPassword())) {
            return Result.fail("两次密码不相同");
        }
        user.setUserNewPassword(passwordEncoder.encode(user.getUserNewPassword()));
        userMapper.updatePassword(user);
        return Result.success("修改成功");
    }

    @Override
    public Result queryEmployee(HnInformation information, int page, int limit) {
        PageHelper.startPage(page,limit);
        List<HnInformation> informations = informationMapper.queryEmployee(information);
        PageInfo<HnInformation> pageInfo = new PageInfo<>(informations);
        return Result.querySuccess(informations,(int)pageInfo.getTotal());
    }

    @Override
    public Result querySalary(HnInformation information, int page, int limit) {
        PageHelper.startPage(page,limit);
        List<HnInformation> informations = informationMapper.querySalary(information);
        PageInfo<HnInformation> pageInfo = new PageInfo<>(informations);
        return Result.querySuccess(informations,(int)pageInfo.getTotal());
    }

    @Override
    public Result salary(Integer userId, Authentication authentication) {
        orderMapper.salary(userId);
        return Result.success("发放工资成功");
    }
}
